#pragma once
#include "requestor.hpp"

namespace MyRpc
{
    namespace client
    {
        class TopicManage
        {
        public:
            using ptr = std::shared_ptr<TopicManage>;
            using SubscribeCB = std::function<void(const std::string&, const std::string&)>;
            TopicManage(const Requestor::ptr& requestor)
                :_requestor(requestor)
            {}
            bool create(const BaseConnection::ptr& conn, const std::string& key) 
            {
                return topicOperate(conn, key, TopicRequestOpType::TOPIC_CREATE);
            }
            bool remove(const BaseConnection::ptr& conn, const std::string& key)
            {
                return topicOperate(conn, key, TopicRequestOpType::TOPIC_REMOVE);
            }
            bool subscribe(const BaseConnection::ptr& conn, const std::string& key, const SubscribeCB& cb)
            {
                addSubscribe(key, cb);
                bool flag = topicOperate(conn, key, TopicRequestOpType::TOPIC_SUBSCRIBE);
                if(flag == false)
                {
                    delSubscribe(key);
                    return false;
                }
                return true;
            }
            bool cancel(const BaseConnection::ptr& conn, const std::string& key)
            {
                delSubscribe(key);
                return topicOperate(conn, key, TopicRequestOpType::TOPIC_CANCEL);
            }
            bool publish(const BaseConnection::ptr& conn, const std::string& key, const std::string& msg)
            {
                return topicOperate(conn, key, TopicRequestOpType::TOPIC_PUBLISH, msg);
            }
            
            // 注册给dispatcher模块 收到publish推送消息之后 给客户端做应答
            void onPublish(const BaseConnection::ptr& conn, const TopicRequest::ptr& msg)
            {
                // 拿出来回应的类型
                TopicRequestOpType optype = msg->topicRequsetOpty();
                // 拿出来请求的主题
                std::string topic = msg->key();
                if(optype != TopicRequestOpType::TOPIC_PUBLISH)
                {
                    LOG(DEBUGLEVEL, "不是推送消息的请求 不做处理!");
                    return;
                }
                // 通过推送的主题寻找对应主题的回调函数
                auto it = selectSubscribe(topic);
                if(!it)
                {
                    LOG(DEBUGLEVEL, "没有找到这个主题对应的回调函数 无法处理!");
                    return;
                }
                // 走到这里就是找到了主题的处理方法
                return it(topic, msg->msg());
            }
        private:
            bool topicOperate(const BaseConnection::ptr& conn, const std::string& key, 
                TopicRequestOpType optype, const std::string& msg = "")
            {
                // 构造请求
                auto req = MessageFactory::create<TopicRequest>();
                req->setId(UUID::uuid());
                req->setKey(key);
                req->setTopicRequsetOpty(optype);
                if(optype == TopicRequestOpType::TOPIC_PUBLISH)
                {
                    req->setMsg(msg);
                }
                req->setMType(MType::REQ_TOPIC);
                BaseMessage::ptr rsp;
                bool flag = _requestor->send(conn, req, rsp);
                if(flag == false)
                {
                    LOG(DEBUGLEVEL, "消息发送失败!");
                    return false;
                }
                // 等待接收应答
                auto rpc_rsp = std::dynamic_pointer_cast<TopicResponse>(rsp);
                if(rpc_rsp->rcode() != RCode::RCODE_OK)
                {
                    LOG(DEBUGLEVEL, "处理结果失败, %s", errReason(rpc_rsp->rcode()).c_str());
                    return false;
                }
                return true;
            }
            void addSubscribe(const std::string& key, const SubscribeCB& cb)
            {
                std::lock_guard<std::mutex> lock(_mtx);
                _topic_cbs.insert(std::make_pair(key, cb));
            }
            void delSubscribe(const std::string& key)
            {
                std::lock_guard<std::mutex> lock(_mtx);
                _topic_cbs.erase(key);
            }
            const SubscribeCB selectSubscribe(const std::string& key)
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _topic_cbs.find(key);
                if(it == _topic_cbs.end())
                {
                    // 没有找到
                    return SubscribeCB();
                }
                return it->second;
            }
        private:
            std::mutex _mtx;
            std::unordered_map<std::string, SubscribeCB> _topic_cbs;  // 对主题和主题收到消息之后的回调函数
            Requestor::ptr _requestor;  // 对客户端的请求消息进行发送
        };
    }
}